package com.yyplatform.admin.platform.role.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.modelmapper.ModelMapper;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;

import com.yyplatform.admin.infra.exception.ErrorCode;
import com.yyplatform.admin.infra.exception.ServiceException;
import com.yyplatform.admin.infra.utils.DateUtils;
import com.yyplatform.admin.platform.role.model.dto.SysUserDTO;
import com.yyplatform.admin.platform.role.model.dto.SysUserDownloadDTO;
import com.yyplatform.admin.platform.role.model.dto.SysUserFormDTO;
import com.yyplatform.admin.platform.role.model.dto.SysUserQueryDTO;
import com.yyplatform.admin.platform.role.model.dto.SysUserUploadDTO;
import com.yyplatform.admin.platform.role.model.entity.SysUserDeptEntity;
import com.yyplatform.admin.platform.role.model.entity.SysUserEntity;
import com.yyplatform.admin.platform.role.model.entity.SysUserPostEntity;
import com.yyplatform.admin.platform.role.model.entity.SysUserRoleEntity;
import com.yyplatform.admin.platform.role.repository.SysUserDeptRepository;
import com.yyplatform.admin.platform.role.repository.SysUserPostRepository;
import com.yyplatform.admin.platform.role.repository.SysUserRepository;
import com.yyplatform.admin.platform.role.repository.SysUserRoleRepository;
import com.yyplatform.admin.platform.role.service.SysUserService;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * Created on 2024-09-13
 */

@Slf4j
@Service
@AllArgsConstructor
public class SysUserServiceImpl implements SysUserService {

    private static final String DEF_PWD = "123456";

    private SysUserRepository sysUserRepository;
    private ModelMapper modelMapper;
    private SysUserDeptRepository sysUserDeptRepository;
    private SysUserPostRepository sysUserPostRepository;

    private SysUserRoleRepository sysUserRoleRepository;


    @Override
    public SysUserDTO get(Long id) {
        SysUserEntity entity = sysUserRepository.getReferenceById(id);
        SysUserDTO sysUserDTO = modelMapper.map(entity, SysUserDTO.class);

        List<SysUserDeptEntity> userDeptEntityList = sysUserDeptRepository.findByUserId(id);
        sysUserDTO.setDeptIdList(userDeptEntityList.stream().map(SysUserDeptEntity::getDeptId).toList());

        List<SysUserPostEntity> userPostEntityList = sysUserPostRepository.findByUserId(id);
        sysUserDTO.setPostIdList(userPostEntityList.stream().map(SysUserPostEntity::getPostId).toList());

        List<SysUserRoleEntity> userRoleEntityList = sysUserRoleRepository.findByUserId(id);
        sysUserDTO.setRoleIdList(userRoleEntityList.stream().map(SysUserRoleEntity::getRoleId).toList());

        return sysUserDTO;
    }

    @Override
    public Page<SysUserDTO> query(SysUserQueryDTO pageQueryDTO) {

        Page<SysUserEntity> entityPage = null;

        if (pageQueryDTO.getDeptId() != null && pageQueryDTO.getDeptId() > 0) {
            entityPage = sysUserRepository.findPageWithDept(
                    pageQueryDTO.getDeptId(),
                    true,
                    pageQueryDTO.getUsername(),
                    pageQueryDTO.getPhone(),
                    pageQueryDTO.getRealName(),
                    DateUtils.getBeginDate(pageQueryDTO.getCreateTimeArr()),
                    DateUtils.getEndDate(pageQueryDTO.getCreateTimeArr()),
                    pageQueryDTO.getPageRequestOrderByIdDesc());
        } else {
            entityPage = sysUserRepository.findPage(
                    true,
                    pageQueryDTO.getUsername(),
                    pageQueryDTO.getPhone(),
                    pageQueryDTO.getRealName(),
                    DateUtils.getBeginDate(pageQueryDTO.getCreateTimeArr()),
                    DateUtils.getEndDate(pageQueryDTO.getCreateTimeArr()),
                    pageQueryDTO.getPageRequestOrderByIdDesc());
        }

        List<SysUserDTO> list = entityPage.stream().map(e -> modelMapper.map(e, SysUserDTO.class)).toList();

        return new PageImpl<>(list, entityPage.getPageable(), entityPage.getTotalElements());
    }

    @Transactional
    @Override
    public void save(SysUserFormDTO formDTO) {

        SysUserEntity checkUserEntity = sysUserRepository.findByUsername(formDTO.getUsername());
        if (checkUserEntity != null) {
            throw ServiceException.of(ErrorCode.DB_KEY_DUMP, "username重复，请重新输入！");
        }


        SysUserEntity entity = new SysUserEntity();
        entity.setUsername(formDTO.getUsername());
        entity.setNickname(formDTO.getRealName());
        entity.setRealName(formDTO.getRealName());


        entity.setEmail(formDTO.getEmail());
        entity.setEnabled(formDTO.getEnabled());
        entity.setFaceUrl("");
        entity.setGender(formDTO.getGender());
        entity.setIsAdmin(false);
        entity.setLastLoginTime(new Date());


        String salt = RandomStringUtils.randomGraph(4);
        String pwd = DEF_PWD;

        String saltMd5 = DigestUtils.md5DigestAsHex(salt.getBytes());
        String pwdMd5 = DigestUtils.md5DigestAsHex(pwd.getBytes());

        String dbMd5 = DigestUtils.md5DigestAsHex((pwdMd5 + saltMd5).getBytes());
        entity.setSalt(salt);
        entity.setPassword(dbMd5);

        entity.setPhone(formDTO.getPhone());
        entity.setPwdResetTime(new Date());
        entity.setRealName(formDTO.getRealName());
        entity.setRemark(formDTO.getRemark());
        entity.setUsername(formDTO.getUsername());

        entity.setPostId(0L);
        entity.setDeptId(0L);

        if (formDTO.getDeptId() != null && formDTO.getDeptId().longValue() > 0) {
            entity.setDeptId(formDTO.getDeptId());
        }

        if (formDTO.getPostId() != null && formDTO.getPostId().longValue() > 0) {
            entity.setPostId(formDTO.getPostId());
        }

        sysUserRepository.save(entity);


        Set<Long> deptIdSet = new HashSet<>();
        List<Long> deptIdList = formDTO.getDeptIdList();

        if (deptIdList != null && deptIdList.size() > 0) {
            deptIdSet = deptIdList.stream().collect(Collectors.toSet());
        }
        saveDept(entity.getId(), formDTO.getDeptId(), deptIdSet);


        Set<Long> postIdSet = new HashSet<>();
        List<Long> postIdList = formDTO.getPostIdList();
        if (!CollectionUtils.isEmpty(postIdList)) {
            postIdSet = postIdList.stream().collect(Collectors.toSet());
        }
        savePost(entity.getId(), formDTO.getPostId(), postIdSet);

        Set<Long> roleIdSet = new HashSet<>();
        List<Long> roleIdList = formDTO.getRoleIdList();
        if (!CollectionUtils.isEmpty(roleIdList)) {
            roleIdSet = roleIdList.stream().collect(Collectors.toSet());
            saveRole(entity.getId(), roleIdSet);
        }

    }

    private void saveRole(Long id, Set<Long> roleIdSet) {
        log.info("save user role info, userid ={}, roleIdsSet=[{}]",
                id, StringUtils.join(roleIdSet, ", "));

        List<SysUserRoleEntity> list = sysUserRoleRepository.findByUserId(id);
        sysUserRoleRepository.deleteAll(list);

        sysUserDeptRepository.flush();


        roleIdSet.forEach(roleId -> {
            SysUserRoleEntity userRoleEntity = new SysUserRoleEntity();
            userRoleEntity.setRoleId(roleId);
            userRoleEntity.setUserId(id);

            sysUserRoleRepository.save(userRoleEntity);
        });


    }

    private void savePost(Long userId, Long postId, Set<Long> postIdSet) {
        log.info("save user post info, userId= {}, postId={}, postIdsSet=[{}]",
                userId, postId, StringUtils.join(postIdSet, ", "));

        List<SysUserPostEntity> list = sysUserPostRepository.findByUserId(userId);
        sysUserPostRepository.deleteAll(list);
        sysUserDeptRepository.flush();


        SysUserPostEntity deptEntity = new SysUserPostEntity();
        deptEntity.setPostId(postId);
        deptEntity.setUserId(userId);

        deptEntity.setRemark("");
        deptEntity.setIsMain(true);

        sysUserPostRepository.save(deptEntity);


        postIdSet.remove(postId);


        postIdSet.forEach(id -> {
            SysUserPostEntity deptEntity2 = new SysUserPostEntity();
            deptEntity2.setPostId(postId);
            deptEntity2.setUserId(userId);

            deptEntity2.setRemark("");
            deptEntity2.setIsMain(true);

            sysUserPostRepository.save(deptEntity2);
        });

    }

    private void saveDept(Long userId, Long deptId, Set<Long> deptIdSet) {
        log.info("save user dept info, userId= {}, deptId={}, deptIdsSet=[{}]",
                userId, deptId, StringUtils.join(deptIdSet, ", "));

        List<SysUserDeptEntity> list = sysUserDeptRepository.findByUserId(userId);
        sysUserDeptRepository.deleteAll(list);

        sysUserDeptRepository.flush();

        SysUserDeptEntity deptEntity = new SysUserDeptEntity();
        deptEntity.setDeptId(deptId);
        deptEntity.setUserId(userId);

        deptEntity.setRemark("");
        deptEntity.setIsMain(true);
        deptEntity.setIsLeader(false);

        sysUserDeptRepository.save(deptEntity);


        deptIdSet.remove(deptId);


        deptIdSet.forEach(id -> {
            SysUserDeptEntity deptEntity2 = new SysUserDeptEntity();
            deptEntity2.setDeptId(id);
            deptEntity2.setUserId(userId);

            deptEntity2.setRemark("");
            deptEntity2.setIsMain(false);
            deptEntity2.setIsLeader(false);

            sysUserDeptRepository.save(deptEntity2);
        });

    }

    @Transactional
    @Override
    public void update(SysUserFormDTO formDTO) {
        SysUserEntity entity = sysUserRepository.getReferenceById(formDTO.getId());


        if (!StringUtils.equals(entity.getUsername(), formDTO.getUsername())) {
            SysUserEntity checkUserEntity = sysUserRepository.findByUsername(formDTO.getUsername());
            if (checkUserEntity != null) {
                throw ServiceException.of(ErrorCode.DB_KEY_DUMP, "username重复，请重新输入！");
            }
        }

        entity.setUsername(formDTO.getUsername());

        entity.setEmail(formDTO.getEmail());
        entity.setEnabled(formDTO.getEnabled());
        entity.setGender(formDTO.getGender());

        entity.setRealName(formDTO.getRealName());


        entity.setPhone(formDTO.getPhone());
        entity.setRemark(formDTO.getRemark());
        entity.setUsername(formDTO.getUsername());

        if (formDTO.getDeptId() != null) {
            entity.setDeptId(formDTO.getDeptId());
        }
        if (formDTO.getPostId() != null) {
            entity.setPostId(formDTO.getPostId());
        }

        sysUserRepository.save(entity);

        Set<Long> deptIdSet = new HashSet<>();
        List<Long> deptIdList = formDTO.getDeptIdList();
        if (!CollectionUtils.isEmpty(deptIdList)) {
            deptIdSet = new HashSet<>(deptIdList);
        }
        saveDept(entity.getId(), formDTO.getDeptId(), deptIdSet);


        Set<Long> postIdSet = new HashSet<>();
        List<Long> postIdList = formDTO.getPostIdList();
        if (!CollectionUtils.isEmpty(postIdList)) {
            postIdSet = new HashSet<>(postIdList);
        }
        savePost(entity.getId(), formDTO.getPostId(), postIdSet);


        Set<Long> roleIdSet = new HashSet<>();
        List<Long> roleIdList = formDTO.getRoleIdList();
        if (!CollectionUtils.isEmpty(roleIdList)) {
            roleIdSet = new HashSet<>(roleIdList);
        }
        saveRole(entity.getId(), roleIdSet);


    }


    @Override
    public void delete(Long id) {
        SysUserEntity entity = sysUserRepository.getReferenceById(id);
        entity.setEnabled(false);
        sysUserRepository.save(entity);
    }

    @Override
    public void resetPwd(Long id) {
        SysUserEntity entity = sysUserRepository.getReferenceById(id);
        String salt = RandomStringUtils.randomGraph(4);
        String pwd = DEF_PWD;

        String saltMd5 = DigestUtils.md5DigestAsHex(salt.getBytes());
        String pwdMd5 = DigestUtils.md5DigestAsHex(pwd.getBytes());

        String dbMd5 = DigestUtils.md5DigestAsHex((pwdMd5 + saltMd5).getBytes());
        entity.setSalt(salt);
        entity.setPassword(dbMd5);


        entity.setPwdResetTime(new Date());

        sysUserRepository.save(entity);
    }


    private Page<SysUserDownloadDTO> find(SysUserQueryDTO pageQueryDTO) {
        Page<SysUserEntity> entityPage = null;

        if (pageQueryDTO.getDeptId() != null && pageQueryDTO.getDeptId() > 0) {
            entityPage = sysUserRepository.findPageWithDept(
                    pageQueryDTO.getDeptId(),
                    true,
                    pageQueryDTO.getUsername(),
                    pageQueryDTO.getPhone(),
                    pageQueryDTO.getRealName(),
                    DateUtils.getBeginDate(pageQueryDTO.getCreateTimeArr()),
                    DateUtils.getEndDate(pageQueryDTO.getCreateTimeArr()),
                    pageQueryDTO.getPageRequestOrderByIdDesc());
        } else {
            entityPage = sysUserRepository.findPage(
                    true,
                    pageQueryDTO.getUsername(),
                    pageQueryDTO.getPhone(),
                    pageQueryDTO.getRealName(),
                    DateUtils.getBeginDate(pageQueryDTO.getCreateTimeArr()),
                    DateUtils.getEndDate(pageQueryDTO.getCreateTimeArr()),
                    pageQueryDTO.getPageRequestOrderByIdDesc());
        }

        List<SysUserDownloadDTO> list1 =
                entityPage.getContent().stream().map(e -> modelMapper.map(e, SysUserDownloadDTO.class)).toList();
        return new PageImpl<>(list1, entityPage.getPageable(), entityPage.getTotalElements());
    }


    @Override
    public List<SysUserDownloadDTO> getDownloadData(SysUserQueryDTO queryDTO) {
        Page<SysUserDownloadDTO> entityPage = find(queryDTO);
        List<SysUserDownloadDTO> list = new ArrayList<>(entityPage.getContent());

        while (entityPage.hasNext()) {
            queryDTO.setPageNum(queryDTO.getPageNum() + 1);
            entityPage = find(queryDTO);
            list.addAll(entityPage.getContent());
        }

        return list;
    }


    @Override
    public void saveUploadData(List<SysUserUploadDTO> cachedDataList) {
        for (SysUserUploadDTO dto : cachedDataList) {
            SysUserEntity checkEntity = sysUserRepository.findByUsername(dto.getUsername());
            if (checkEntity != null) {
                throw ServiceException.of(ErrorCode.DB_KEY_DUMP, "username重复，请重新输入！");
            }

        }


        for (SysUserUploadDTO dto : cachedDataList) {

            SysUserEntity entity = new SysUserEntity();

            entity.setUsername(dto.getUsername());
            entity.setNickname(dto.getRealName());
            entity.setRealName(dto.getRealName());
            entity.setPhone(dto.getPhone());
            entity.setEmail(dto.getEmail());
            entity.setGender(dto.getGender());

            entity.setEnabled(false);
            entity.setFaceUrl("");
            entity.setDeptId(0L);
            entity.setPostId(0L);
            entity.setRemark("");
            entity.setIsAdmin(false);

            entity.setLastLoginTime(new Date());
            entity.setPwdResetTime(new Date());


            String salt = RandomStringUtils.randomGraph(4);
            String saltMd5 = DigestUtils.md5DigestAsHex(salt.getBytes());
            String pwdMd5 = DigestUtils.md5DigestAsHex(DEF_PWD.getBytes());
            String dbMd5 = DigestUtils.md5DigestAsHex((pwdMd5 + saltMd5).getBytes());
            entity.setSalt(salt);
            entity.setPassword(dbMd5);


            sysUserRepository.save(entity);


        }
    }
}
